package Zixin.sql;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.dbcp.BasicDataSource;

/**
 * 数据库工�?
 * 连接数据�?操作数据�?
 * 注意：此工具只�?用使用MVC框架的数据库连接操作
 * @author wendao
 *
 */
public class DatabaseOperationToolsMVC {

	private static BasicDataSource myDataSource;	//使用dbcp连接数据库（MVC框架�?
	
	public static BasicDataSource getMyDataSource() {
		return myDataSource;
	}

	public static void setMyDataSource(BasicDataSource myDataSource) {
		DatabaseOperationToolsMVC.myDataSource = myDataSource;
	}

	private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");	//时间格式
	
	/**
	 * 获取数据库连接对象的公共方法
	 * @return 数据库连接对�?
	 */
	public static Connection getConnectionDB() {
		Connection conn = null;
		try {
			conn = myDataSource.getConnection();
		} catch (SQLException e) {
			System.err.println();
			System.err.println("===***===�?��");
			System.err.println("===***==="+sdf.format(new Date()));
			System.err.println("===***===连接MySQL数据库失败，请检�?连接路径><账户><密码>是否正确");
			e.printStackTrace();
			System.err.println("===***==="+sdf.format(new Date()));
			System.err.println("===***===结束");
			System.err.println();
		}
		return conn;
	}
	
	/**
	 * 关闭数据库连接对象，释放资源的公共方�?
	 * @param conn  数据库连接对�?
	 * @param pstm  语句执行对象
	 * @param rs    结果集对�?
	 */
	public static void closeDB(Connection conn, PreparedStatement pstm, ResultSet rs){
		try {
			if(rs!=null)
				rs.close();
			if(pstm!=null)
				pstm.close();
			if(conn!=null)
				conn.close();
		} catch (SQLException e) {
			System.err.println("===***===数据库关闭出错");
			e.printStackTrace();
		}
		
	}
	
	/**
	 * 公共--保存或更新方�?（sql语句,Object[]参数数组）；
	 * 详情：对数据库进�?insert（新增）/update（修改）/delete（删除）�?
	 * 注意：此方法�?saveOrUpdateDB(String sql, List<Object> list)效果�?���?
	 * 		只是传参方式不同，可灵活使用任意�?��
	 * @param sql 操作数据库的SQL语句
	 * @param objs Object参数数组，如：new Object[]{参数1,参数2,.......}
	 * @return true or false（执行成功或失败�?
	 */
	public static boolean saveOrUpdateDB(String sql, Object[] objs){
		//获取数据库连接对�?
		Connection conn = getConnectionDB();
		//获取语句执行对象
		PreparedStatement pstm = null;
		try {
			pstm = conn.prepareStatement(sql);
			//用户传�?了参数�?，说明SQL中有占位�?
			if(objs != null && objs.length > 0){
				int objSize = objs.length;
				for (int i = 0; i < objSize; i++) {
					if(objs[i] == null)
						objs[i]="";
					pstm.setObject(i+1, objs[i]);
				}
			}
			//执行更新操作,执行成功返回true
			if(pstm.executeUpdate()>0){
				return true;
			}
		} catch (SQLException e) {
			System.err.println("===***===数据保存或更新出?");
			e.printStackTrace();
		}finally{
			closeDB(conn, pstm, null);//关闭连接，释放资�?
		}
		return false;
	}
	
	/**
	 * 公共方法--保存或更新方�?(sql语句,list参数集合)�?
	 * 详情：可对数据库进行 insert（新增）/update（修改）/delete（删除）�?
	 * 注意：此方法�?saveOrUpdateDB(String sql, Object[] objs)效果�?���?
	 * 		只是传参方式不同，可灵活使用任意�?��
	 * @param sql 操作数据库的SQL语句
	 * @param list list参数数组
	 * @return true or false（执行成功或失败�?
	 */
	public static boolean saveOrUpdateDB(String sql, List<Object> list){
		Connection conn = getConnectionDB();	//获取数据库连接对�?
		PreparedStatement pstm = null;	//获取语句执行对象
		try {
			pstm = conn.prepareStatement(sql);
			//用户传�?了参数�?，说明SQL中有占位�?
			if(list != null && list.size() > 0){
				int listSize = list.size();
				for (int i = 0; i < listSize; i++) {
					if(list.get(i) == null){
						pstm.setObject(i+1, "");
					}else {
						pstm.setObject(i+1, list.get(i));
					}
				}
			}
			//执行更新操作,执行成功返回true
			if(pstm.executeUpdate()>0){
				return true;
			}
		} catch (SQLException e) {
			System.err.println("===***===数据保存或更新出错");
			e.printStackTrace();
		}finally{
			closeDB(conn, pstm, null);//关闭连接，释放资�?
		}
		return false;
	}
	
	/**
	 * 公共方法--同时执行2条或2条以上保存或更新方法�?
	 * 保证�?��语句同时成功执行，失败一条语句则全部回滚事务并返回false�?
	 * 详情：可对数据库进行 insert（新增）/update（修改）/delete（删除）�?
	 * @param listSql list集合SQL语句，即是多条SQL语句
	 * @param listPram list集合的参数集合，即是第N条SQL语句的第N条SQL参数
	 * @return true or false（执行成功或失败�?
	 */
	public static boolean manySaveOrUpdateDB(List<String> listSql, List<List<Object>> listPram) {
		Connection conn = null;
		PreparedStatement pstm = null;
		try {
			if (listSql != null && listSql.size() > 0  && listPram != null && listPram.size() > 0) {
				int listSqlSize = listSql.size();
				int listPramSize = listPram.size();
				//判断SQL语句与SQL参数的条数是否相�?
				if (listSqlSize == listPramSize) {
					conn = getConnectionDB();	//获取数据库连接对�?
					conn.setAutoCommit(false);	//关闭自动提交事件
					for (int i = 0; i < listSqlSize; i++) {
						pstm = conn.prepareStatement(listSql.get(i));
						if (listPramSize > 0) {
							List<Object> pram = listPram.get(i);
							if (pram != null && pram.size() > 0) {
								int pramSize = pram.size();
								for (int j = 0; j < pramSize; j++) {
									if (pram.get(j) == null) {
										pstm.setObject(j+1, "");
									} else {
										pstm.setObject(j+1, pram.get(j));
									}
								}
							}
						}
						pstm.executeUpdate();//执行更新操作
					}
					conn.commit();	//提交事务
					return true;
				}
			}
		} catch (SQLException e) {
			System.err.println("===***===多条SQL语句�?insert(新增)/update(修改)/delete(删除)执行失败，并进行回滚事务");
			e.printStackTrace();
			try {
				conn.rollback();	//有语句执行报错异�?执行回滚操作
			} catch (SQLException e1) {
				System.err.println("===***===多条SQL语句�?insert(新增)/update(修改)/delete(删除)回滚事务失败");
				e1.printStackTrace();
			}
		} finally {
			closeDB(conn, pstm, null);//关闭连接，释放资�?
		}
		return false;
	}
	
	/**
	 * 公共方法--查询单个1（sql语句，Object[]参数数组�?
	 * 根据SQL语句查询，返回一个对象或者一条数�?
	 * 注意：此方法�?queryOneData(String sql, List<Object> listPram)效果�?���?
	 * 		只是传参方式不同，可灵活使用任意�?��
	 * @param sql 要执行的SQL语句
	 * @param objs SQL语句参数数组
	 * @return map对象
	 */
	public static Map<String, Object> queryOneData(String sql, Object[] objs){
		Connection conn = null;// 获取数据库连接对�?
		PreparedStatement pstm = null; // 获取语句执行对象
		ResultSet rs = null;
		Map<String, Object> map = null;	//数据结果
		try {
			conn = getConnectionDB();
			pstm = conn.prepareStatement(sql);
			if (objs != null) {
				int objsSize = objs.length;
				for (int i = 0; i < objsSize; i++) {
					if (objs[i] == null) {
						pstm.setObject(i + 1, "");
					} else {
						pstm.setObject(i + 1, objs[i]);
					}
				}
			}
			rs = pstm.executeQuery();
			if (rs.next()) {
				map = new HashMap<String, Object>();
				ResultSetMetaData rsmd = rs.getMetaData();
				int resultSize = rsmd.getColumnCount();
				for (int i = 1; i <= resultSize; i++) {
					String columnName = rsmd.getColumnLabel(i);
					if (rs.getString(columnName) != null && rs.getString(columnName).length() > 0) {
						map.put(columnName, rs.getString(columnName));
					} else {
						map.put(columnName, "");
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			closeDB(conn, pstm, rs);//关闭连接，释放资�?
		}
		return map;
	}
	
	/**
	 * 公共方法--查询单个2（sql语句，List参数集合�?
	 * 根据SQL语句查询，返回一个对象或者一条数据；
	 * 注意：此方法�?queryOneData(String sql, Object[] objs)效果�?���?
	 * 		只是传参方式不同，可灵活使用任意�?��
	 * @param sql 要执行的SQL语句
	 * @param objs SQL语句list参数集合
	 * @return map对象
	 */
	public static Map<String, Object> queryOneData(String sql, List<Object> listPram){
		Connection conn = null;// 获取数据库连接对�?
		PreparedStatement pstm = null; // 获取语句执行对象
		ResultSet rs = null;
		Map<String, Object> map = null;	//数据结果
		try {
			conn = getConnectionDB();
			pstm = conn.prepareStatement(sql);
			if (listPram != null) {
				int listSize = listPram.size();
				for (int i = 0; i < listSize; i++) {
					if (listPram.get(i) == null) {
						pstm.setObject(i + 1, "");
					} else {
						pstm.setObject(i + 1, listPram.get(i));
					}
				}
			}
			rs = pstm.executeQuery();
			if (rs.next()) {
				map = new HashMap<String, Object>();
				ResultSetMetaData rsmd = rs.getMetaData();
				int resultSize = rsmd.getColumnCount();
				for (int i = 1; i <= resultSize; i++) {
					String columnName = rsmd.getColumnLabel(i);
					if (rs.getString(columnName) != null && rs.getString(columnName).length() > 0) {
						map.put(columnName, rs.getString(columnName));
					} else {
						map.put(columnName, "");
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			closeDB(conn, pstm, rs);//关闭连接，释放资�?
		}
		return map;
	}
	
	/**
	 * 公共方法--查询多个（sql语句，list参数集合）；
	 * 根据SQL语句查询，返回多条数据的List<Map<String, Object>>
	 * @param sql 要执行的SQL语句
	 * @param listPram SQL语句list参数集合
	 * @return List<Map<String, Object>> map对象集合
	 */
	public static List<Map<String, Object>> queryManyData(String sql, List<Object> listPram){
		Connection conn = null;// 获取数据库连接对�?
		PreparedStatement pstm = null; // 获取语句执行对象
		ResultSet rs = null;
		List<Map<String, Object>> mapList = null;
		try {
			conn = getConnectionDB();
			pstm = conn.prepareStatement(sql);
			if (listPram != null && listPram.size() > 0) {
				int size = listPram.size();
				for (int i = 0; i < size; i++) {
					if (listPram.get(i) == null) {
						pstm.setObject(i + 1, "");
					} else {
						pstm.setObject(i + 1, listPram.get(i));
					}
				}
			}
			rs = pstm.executeQuery();
			mapList = new ArrayList<Map<String, Object>>();
			
			ResultSetMetaData rsmd = rs.getMetaData();
			int resultSize = rsmd.getColumnCount();
			while (rs.next()) {
				Map<String, Object> result = new HashMap<String, Object>();
				for (int i = 1; i <= resultSize; i++) {
					String columnName = rsmd.getColumnLabel(i);
					if (rs.getString(columnName) != null) {
						result.put(columnName, rs.getString(columnName));
					} else {
						result.put(columnName, "");
					}
				}
				mapList.add(result);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			closeDB(conn, pstm, rs);//关闭连接，释放资�?
		}
		return mapList;
	}
	
	/**
	 * 公共方法--根据SQL语句查询返回指定列名的�?�?
	 * 如：指定name，则返回String形的值�?
	 * 注意：此方法�?getObjectByqueryOneData(String sql, List<Object> listPram, String columnName)效果�?���?
	 * 		只是传参的方式不同，可灵活使用任意一�?
	 * @param sql 要执行的SQL语句
	 * @param listPram list参数集合
	 * @param columnName 返回指定的列�?
	 * @return 返回指定的列名的�?
	 */
	public static Object getObjectByqueryOneData(String sql, Object[] objs, String columnName) {
		return queryOneData(sql, objs).get(columnName);
	}
	
	/**
	 * 公共方法--根据SQL语句查询返回指定列名的�?�?
	 * 如：指定name，则返回String形的值�?
	 * 注意：此方法�?getObjectByqueryOneData(String sql, Object[] objs, String columnName)效果�?���?
	 * 		只是传参的方式不同，可灵活使用任意一�?
	 * @param sql 要执行的SQL语句
	 * @param listPram list参数集合
	 * @param columnName 返回指定的列�?
	 * @return 返回指定的列名的�?
	 */
	public static Object getObjectByqueryOneData(String sql, List<Object> listPram, String columnName) {
		return queryOneData(sql, listPram).get(columnName);
	}

	
	
}
